package sg.edu.nus.iss.phoenix.schedule.service;

import java.sql.Date;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;

import sg.edu.nus.iss.phoenix.core.dao.DAOFactoryImpl;
import sg.edu.nus.iss.phoenix.schedule.dao.ScheduleDAO;
import sg.edu.nus.iss.phoenix.schedule.entity.ProgramSlot;
import sg.edu.nus.iss.phoenix.schedule.entity.Schedule;

/**
 * This service class handles all business logic for Schedule and ProgramSlot object.
 * @author Goh Zhe Yi, Karthic Kumar, Ramprasad, Gayathri
 *
 */
public class ScheduleService {
	DAOFactoryImpl factory;
	ScheduleDAO scheduleDAO;

	public ScheduleService() {
		super();
		factory = new DAOFactoryImpl();
		scheduleDAO = factory.getScheduleDAO();
	}

	/**
	 * This method is used to create a new Schedule object into system
	 * @param schedule
	 * 			Schedule object to be inserted 
	 */
	public void createSchedule(Schedule schedule) {
		try {
			scheduleDAO.createSchedule(schedule);
		} catch (SQLException e) {

		}
	}
	
	/**
	 * This method is used to save a modified Schedule object into system
	 * @param schedule
	 * 			modified Schedule object to be saved 
	 */
	public void modifySchedule(Schedule schedule) {
		validateModifiedSchedule(schedule);
		try {
			scheduleDAO.createSchedule(schedule);
		} catch (SQLException e) {

		}
	}
	
	/**
	 * This method is used to delete a Schedule object from the system
	 * @param schedule
	 * 			Schedule object to be inserted into system
	 */
	public void deleteSchedule(Schedule schedule) {
		try {
			scheduleDAO.deleteSchedule(schedule);
		} catch (SQLException e) {

		}
	}
	
	/**
	 * This method validates the modified schedule object
	 * @param schedule
	 * 			 Schedule object to be validated
	 * @return True - if validation is successful, False - if validation fails
	 *			
	 * 			
	 */
	private boolean validateModifiedSchedule(Schedule schedule) {

		return true;
	}
	
	/**
	 * This get-method is retrieving the schedule object based on the date given
	 * @param date a String type object which stores the date
	 * @return Schedule object which contains the date given
	 * @throws Exception
	 */
	public Schedule getSchedule(String date) throws Exception {
		Schedule schedule = new Schedule();
		try {
			schedule = scheduleDAO.getSchedule(date);
		} catch (SQLException e) {

		}
		return schedule;
	}


	/**
	 * This get-method gets a hash-map of the date and schedule of the week (Mon-Sun) which contains the date 
	 * @param date a date of any day of the week
	 * @return Map<Date,Schedule> which is the week that contains the date given 
	 * @throws Exception
	 */
	public Map<Date, Schedule> getWeeklySchedule(Date date) throws Exception{
		HashMap<Date, Schedule> weeklySchedule = new HashMap<Date, Schedule>();
		Date firstDayOfWeek = DateUtil.getFirstDateOfTheWeek(date);
		try {
			for (int i = 1; i <= 7; i++) {
				Date d = DateUtil.addDays(firstDayOfWeek, i);
				Schedule schedule = this.getSchedule(DateUtil
						.convertToMySQLDateFormat1(d.toString()));
				weeklySchedule.put(d, schedule);
			}
		} catch (SQLException e) {
			throw e;
		}       
		Map<Date, Schedule> treeMap = new TreeMap<Date, Schedule>(weeklySchedule);
		
		return treeMap;
	}
	
	/**
	 * This create-method, creates a copy of the weekly schedule based on the source date and passes it to destination date.
	 * @param fromDate Date object which is in the source week to be copied
	 * @param toDate Date object which is in the destination date of the week to copy
	 * @return Tree-Map<Date,Schedule> which is the new week schedule
	 * @throws Exception
	 */
	public Map<Date, Schedule> CopyWeeklySchedule(Date fromDate, Date toDate)
			throws Exception {
		HashMap<Date, Schedule> tempSchedule = new HashMap<Date, Schedule>();
		HashMap<Date, Schedule> weeklySchedule = new HashMap<Date, Schedule>();
		Date firstDayOfWeekFromDate = DateUtil.getFirstDateOfTheWeek(fromDate);
		Date firstDayOfWeekToDate = DateUtil.getFirstDateOfTheWeek(toDate);
		try {
			for (int i = 1; i <= 7; i++) {
				Date from = DateUtil.addDays(firstDayOfWeekFromDate, i);
				Schedule schedule = this.getSchedule(DateUtil
						.convertToMySQLDateFormat1(from.toString()));
				tempSchedule.put(from, schedule);
			}

			for (int i = 1; i <= 7; i++) {
				Date from = DateUtil.addDays(firstDayOfWeekFromDate, i);
				Date targetDate = DateUtil.addDays(firstDayOfWeekToDate, i);
				if (!tempSchedule.get(from).equals(null)) {
					ArrayList<ProgramSlot> oldProgramList = tempSchedule.get(from).getProgramSlotList();
					// Schedule schedule =
					// this.getSchedule(DateUtil.convertToMySQLDateFormat1(to.toString()));
					ArrayList<ProgramSlot> newProgramList = new ArrayList<ProgramSlot>();
					for (ProgramSlot fromSlot : oldProgramList) {
						ProgramSlot toSlot = new ProgramSlot();
						toSlot.setDateOfProgram(targetDate.toString());
						toSlot.setDuration(fromSlot.getDuration());
						toSlot.setPresenter(fromSlot.getPresenter());
						toSlot.setProducer(fromSlot.getProducer());
						toSlot.setStartTime(targetDate.toString()+ " "+ DateUtil.convertToMySQLTimeFormat(fromSlot.getStartTime()));
						toSlot.setProgramName(fromSlot.getProgramName());
						toSlot.setProgramSlotId(fromSlot.getProgramSlotId());
						this.createProgramSlot(toSlot);
						newProgramList.add(toSlot);
					}
					Schedule newSchedule = new Schedule();
					newSchedule.setDateOfSchedule(targetDate.toString());
					newSchedule.setProgramSlotList(newProgramList);
					weeklySchedule.put(targetDate, newSchedule);
				}else{
					weeklySchedule.put(targetDate, new Schedule());
				}
			}
		} catch (SQLException e) {
			throw e;
		}

		Map<Date, Schedule> treeMap = new TreeMap<Date, Schedule>(weeklySchedule);
		
		return treeMap;
	}
	
	/**
	 * This get-method is getting an arraylist of schedule based on the start date and end date
	 * @param startDate Date object for the first date in the list
	 * @param endDate Date object for the last date in the list
	 * @return ArrayList<Schedule> which contains all the schedule objects starting from the startDate to the endDate
	 * @throws Exception
	 */
	public ArrayList<Schedule> getScheduleList(Date startDate, Date endDate)
			throws Exception {
		ArrayList<Schedule> scheduleList = new ArrayList<Schedule>();
		try {
			scheduleList = scheduleDAO.getListOfSchedule(startDate, endDate);
		} catch (SQLException e) {

		}
		return scheduleList;
	}

	/**
	 * This create-method, creates the program slot object to be inserted into the system
	 * @param programSlot
	 * @throws Exception
	 */
	public void createProgramSlot(ProgramSlot programSlot) throws Exception {
		scheduleDAO.createProgramSlot(programSlot);
	}

	/**
	 * This method validates the modified schedule
	 * @param startTime 
	 * @param endTime
	 * @return True if successful, False if fail
	 * @throws SQLException
	 */
	public void validateToSaveSchedule(java.util.Date startTime, java.util.Date endTime) throws SQLException, Exception {
		String st = "";
		String et = "";		

		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		st = format.format(startTime);
		et = format.format(endTime);		
		
		int i = scheduleDAO.getScheduleCountBetweenStartAndEndDate(st, et);
		if( i != 0)
			throw new Exception("Program Slot overlaps with the next slot!! Please delete the slot before overriding");
		
	}
	
	/**
	 * This method is to save the modified program slot into the system
	 * @param programSlot
	 * 				modified Program Slot object to be saved
	 * @throws SQLException
	 */
	public void validateProgramSlot(ProgramSlot programSlot) throws Exception{
		
		Calendar c = Calendar.getInstance();
		c.setTime(DateUtil.convertStringTodate(programSlot.getStartTime()));
		int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
		
		if (dayOfWeek == 1)
		{
		Calendar c1 = Calendar.getInstance();
		c1.setTime(DateUtil.convertStringTodate(programSlot.getStartTime()));
		System.out.println("given date in pgm"+ c.getTime());
		String newTime = programSlot.getDuration();
		String[] tokens = newTime.split("[:]");
		int min = (Integer.parseInt(tokens[0]) * 60)+ Integer.parseInt(tokens[1]);
		System.out.println("given minutes"+ min);
		c.add(Calendar.MINUTE, min);
		System.out.println("added date"+ c.getTime());
		System.out.println("which day of week"+ c.get(Calendar.DAY_OF_WEEK));
		if(c.get(Calendar.DAY_OF_WEEK) != 1)
			throw new Exception("Select Program Slot duration which ends within this week");
		}
		
		
	}
	
	/**
	 * This method saves the modified program slot in the system
	 * @param programSlot
	 * 			modified ProgramSlot object to be saved into the system
	 * @throws SQLException
	 */
	public void modifyProgramSlot(ProgramSlot programSlot) throws SQLException {
		/*java.util.Date d = new java.util.Date();
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		d = format.parse(programSlot.getStartTime());
		
		java.util.Date ed = new java.util.Date();
		ed = d+ 3;
		
		if(validateToSaveSchedule())*/
		scheduleDAO.modifyProgramSlot(programSlot);
	}
	
	/**
	 * This method is to delete the program slot from the system
	 * @param programSlotId
	 * 				ID of the program slot to be deleted
	 * @throws SQLException
	 */
	public void deleteProgramSlot(int programSlotId) throws SQLException {
		scheduleDAO.deleteProgramSlot(programSlotId);
	}
	
}
